import {defineComponent, reactive, ref, watch} from 'vue';
import {
    AutoComplete,
    Button,
    Cascader,
    Col,
    DatePicker,
    Divider,
    Form,
    Input,
    message,
    Row,
    Select,
    TimePicker,
    TreeSelect,
} from "ant-design-vue";
import {DefaultOptionType} from "ant-design-vue/es/vc-cascader";
import {JSX} from "vue/jsx-runtime";

export default defineComponent({
    components: {
        Form, Input, Select, DatePicker, TimePicker, TreeSelect, Cascader, Button, Row, Col, Divider,
    },
    props: {
        fields: {
            type: Array as () => Array<FieldConfig>,
            required: true,
        },
        modelValue: {
            type: Object as () => Record<string, any>,
            required: true,
        },
        layout: {
            type: String as () => 'compact' | 'default',
            default: 'compact',
        },
        onSubmit: {
            type: Function as () => (values: Record<string, any>) => void,
            required: true,  // 提交动作通过props提供
        },
    },
    emits: ['update:modelValue'],
    setup(props, {emit}) {
        const formRef = ref<any>(null);
        const formState = reactive<Record<string, any>>({});
        Object.assign(formState, props.modelValue);

        watch(() => props.modelValue, (newValue) => {
            Object.assign(formState, newValue);
        });

        watch(formState, (newValue) => {
            emit('update:modelValue', newValue);
        }, {deep: true});

        const componentMap: Record<string, (field: FieldConfig) => JSX.Element> = {
            input: renderInput,
            textarea: renderTextArea,
            date: renderDatePicker,
            time: renderTimePicker,
            datetime: renderDateTimePicker,
            select: renderSelect,
            treeselect: renderTreeSelect,
            cascader: renderCascader,
            autocomplete: renderAutoComplete,
        };

        function renderAutoComplete(field: FieldConfig): JSX.Element {
            return (
                <AutoComplete
                    v-model={[formState[field.name], 'value']}
                    options={field.options?.dataSource?.map(opt => ({value: opt}))}
                    filterOption={(inputValue, option) => option!.value.toUpperCase().indexOf(inputValue.toUpperCase()) !== -1}
                    {...field.options}
                />
            );
        }

        function renderInput(field: FieldConfig): JSX.Element {
            return <Input v-model={[formState[field.name], 'value']} {...field.options} />;
        }

        function renderTextArea(field: FieldConfig): JSX.Element {
            return <Input.TextArea v-model={[formState[field.name], 'value']} {...field.options} />;
        }

        function renderDatePicker(field: FieldConfig): JSX.Element {
            return <DatePicker v-model={[formState[field.name], 'value']} {...field.options} />;
        }

        function renderTimePicker(field: FieldConfig): JSX.Element {
            return <TimePicker v-model={[formState[field.name], 'value']} {...field.options} />;
        }

        function renderDateTimePicker(field: FieldConfig): JSX.Element {
            return <DatePicker showTime v-model={[formState[field.name], 'value']} {...field.options} />;
        }

        function renderSelect(field: FieldConfig): JSX.Element {
            return (
                <Select v-model={[formState[field.name], 'value']} {...field.options}>
                    {field.optionData?.map(opt => (
                        <Select.Option key={opt.value} value={opt.value}>
                            {opt.label}
                        </Select.Option>
                    ))}
                </Select>
            );
        }

        function renderCascader(field: FieldConfig): JSX.Element {
            const filter = (inputValue: string, path: DefaultOptionType[]) =>
                path.some(option => (option.label as string).toLowerCase().indexOf(inputValue.toLowerCase()) > -1);

            return (
                <Cascader
                    v-model={[formState[field.name], 'value']}
                    showSearch={{filter}}
                    options={field.optionData}
                    expandTrigger="hover"
                    {...field.options}
                />
            );
        }

        function renderTreeSelect(field: FieldConfig): JSX.Element {
            return (
                <TreeSelect
                    v-model={[formState[field.name], 'value']}
                    treeData={field.optionData}
                    showSearch
                    filterTreeNode={(inputValue, treeNode) => treeNode.label.toLowerCase().includes(inputValue.toLowerCase())}
                    treeDefaultExpandAll
                    {...field.options}
                />
            );
        }

        function renderFormGroup(field: FieldConfig): JSX.Element {
            return (
                <>
                    <Divider orientation="left">{field.label}</Divider>
                    <div class="form-group">
                        {field.children?.map(childField => (
                            <div class="form-item" key={childField.name}>
                                {renderFormItem(childField)}
                            </div>
                        ))}
                    </div>
                </>
            );
        }

        const renderFormItem = (field: FieldConfig): JSX.Element | null => {
            if (field.type === 'group') {
                return renderFormGroup(field);
            }

            const componentRenderer = componentMap[field.type];
            if (!componentRenderer) {
                return null;
            }

            const rules = field.required ? [{required: true, message: `请输入${field.label}`}] : [];
            return (
                <Form.Item key={field.name} label={field.label} name={field.name} rules={rules}
                           validateTrigger={['blur']}>
                    {componentRenderer(field)}
                </Form.Item>
            );
        };

        const renderFormFields = () => {
            return props.fields.map(field => (
                field.type === 'group' ? (
                    <div key={field.name}>
                        {renderFormGroup(field)}
                    </div>
                ) : (
                    <div class="form-item" key={field.name}>
                        {renderFormItem(field)}
                    </div>
                )
            ));
        };

        return () => (
            <Form ref={formRef} model={formState} onFinish={() => props.onSubmit(formState)}>
                {renderFormFields()}
                <Form.Item>
                    <Button
                        type="primary"
                        htmlType="submit"
                        onClick={() => {
                            formRef.value.validate().then(() => {
                                message.success('表单校验通过!');
                            }).catch(error => {
                                message.error('表单校验未通过!', error);
                            });
                        }}
                    >
                        提交
                    </Button>
                </Form.Item>
            </Form>
        );
    },
});

interface OptionItem {
    value: string;
    label: string;
    children?: Array<OptionItem>;
}

export interface FieldConfig {
    type: string;
    label: string;
    name: string;
    required?: boolean;
    optionData?: Array<OptionItem>;
    options?: Record<string, any>;
    children?: Array<FieldConfig>;
}